package com.biscuit.page.basicservice.service;

import com.biscuit.common.base.BaseModelResponse;
import com.biscuit.page.basicservice.api.model.request.user.*;
import com.biscuit.page.basicservice.api.model.response.user.UserInfoAResp;
import com.biscuit.page.basicservice.bean.RedisCache;
import com.biscuit.page.basicservice.model.constant.redis.RedisAuthorizationConstant;
import com.biscuit.page.basicservice.model.entities.mysql.SysUser;
import com.biscuit.page.basicservice.model.enums.BaseEntityEnum;
import com.biscuit.page.basicservice.model.exception.BaseException;
import com.biscuit.page.basicservice.persistence.dao.UserDao;
import com.biscuit.page.basicservice.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author biscuit
 * @createTime 2024/6/25 10:25
 */
@Slf4j
@Service
public class UserService {

    @Resource
    private UserDao userDao;

    @Resource
    private RedisCache redisCache;

    @Resource
    private CommonService commonService;

    public UserInfoAResp getUserInfo(UserIdAReq req) {
        return null;
    }

    public void execResetPasswordDefault(UserIdAReq req) {
        // 根据用户Id查询用户信息
        SysUser user = this.userDao.getById(req.getUserId());

        // 校验用户信息
        BaseExceptionUtil.throwException(
                Objects.nonNull(user) && user.getIsDeleted().intValue() == BaseEntityEnum.NOT_DELETED.getValue(),
                "用户信息不存在"
        );
        BaseExceptionUtil.throwException(user.getStatus() == 1, "用户状态异常");

        // MD5 加密默认密码 123456789
        String defaultPassword = MD5Util.md5("123456789");

        // 重置用户密码
        this.userDao.updatePasswordByUserId(req.getUserId(), defaultPassword);
        log.info("UserService execResetPasswordDefault，userId -> {}，重置密码为默认密码", req.getUserId());
    }

    public void execResetPassword(UserResetPasswordAReq req) {
        // 校验两次是否密码是否一致
        BaseExceptionUtil.throwException(req.getPassword().equals(req.getVerifyPassword()), "两次输入密码不一致");

        // 校验验证码

        // 根据用户账号获取用户信息（账号/密码）
        SysUser user = this.userDao.getByAccount(req.getAccount());

        // 校验用户信息
        BaseExceptionUtil.throwException(
                Objects.nonNull(user) && user.getIsDeleted().intValue() == BaseEntityEnum.NOT_DELETED.getValue(),
                "用户信息不存在"
        );
        BaseExceptionUtil.throwException(user.getStatus() == 1, "用户状态异常");

        // 校验验证码
    }

    public void updateAvatarAndNickName(UserUpdateAvatarAndNickNameAReq req) {
        // 参数校验
        BaseExceptionUtil.throwException(req.getNickName().length() < 20, "用户昵称过长");

        // 根据 用户ID 查询用户信息
        SysUser user = this.userDao.getById(req.getUserId());

        // 判断当前用户是否存在头像，存在头像时不允许修改为空
        if (StringUtils.isNotBlank(user.getAvatar())) {
            BaseExceptionUtil.throwException(StringUtils.isNotBlank(req.getAvatar()), "用户头像为空");
        }

        // 校验用户昵称是否全部是空格
        BaseExceptionUtil.throwException(StringUtils.isNotBlank(req.getNickName().replace(" ", "")), "用户异常非法");

        // 修改用户信息
        SysUser updateUser = new SysUser();
        updateUser.setId(req.getUserId());
        updateUser.setNickName(req.getNickName().replace(" ", ""));
        updateUser.setAvatar(StringUtils.isNotBlank(req.getAvatar()) ? req.getAvatar(): null);
        updateUser.setLastUpdateTime(LocalDateTime.now());
        this.userDao.updateById(updateUser);



        // 异步更新缓存的用户信息
        BaseThreadUtil.async(() -> {
            // 查询最新的用户信息
            SysUser sysUser = this.userDao.getById(req.getUserId());

            // 组装用户信息缓存key
            String cacheKey = RedisAuthorizationConstant.AUTHORIZATION_USER_PREFIX + sysUser.getId();

            // 缓存用户信息
            this.redisCache.setObject(cacheKey, sysUser, 2, TimeUnit.DAYS);
        });
    }

    public void updateEmail(UserUpdateEmailAReq req) {
        // 验证校验通过标识是否合法
        try {
            JwtUtil.verify(req.getCheckKey());
            String target = JwtUtil.getUserKey(req.getCheckKey());
            BaseExceptionUtil.throwException(req.getEmail().equals(target), "");
        } catch (Exception e) {
            throw new BaseException("邮箱验证码校验通过标识异常，请重新进行验证");
        }

        // 校验邮箱是否合法
        BaseExceptionUtil.throwException(RegexUtil.validateEmail(req.getEmail()), "邮箱格式错误");

        // 根据 用户ID，查询用户信息
        SysUser user = this.userDao.getById(req.getUserId());

        // 判断邮箱是否重复
        BaseExceptionUtil.throwException(!user.getEmail().equals(req.getEmail()), "新邮箱与原邮箱重复");

        // 根据邮箱查询用户信息
        List<SysUser> userList =  this.userDao.listByEmail(req.getEmail())
                .stream().filter(x -> x.getId().intValue() != user.getId()).collect(Collectors.toList());

        // 判断邮箱是否重复
        BaseExceptionUtil.throwException(CollectionUtils.isEmpty(userList), "该邮箱已被其他账号使用");

        // 更新用户邮箱
        SysUser updateEmailUser = new SysUser();
        updateEmailUser.setEmail(req.getEmail());
        updateEmailUser.setId(user.getId());
        updateEmailUser.setLastUpdateTime(LocalDateTime.now());
        this.userDao.updateById(updateEmailUser);

        // 异步更新缓存的用户信息
        BaseThreadUtil.async(() -> {
            // 查询最新的用户信息
            SysUser sysUser = this.userDao.getById(req.getUserId());

            // 组装用户信息缓存key
            String cacheKey = RedisAuthorizationConstant.AUTHORIZATION_USER_PREFIX + sysUser.getId();

            // 缓存用户信息
            this.redisCache.setObject(cacheKey, sysUser, 2, TimeUnit.DAYS);
        });
    }

    public void updateMobile(UserUpdateMobileAReq req) {
        // 验证校验通过标识是否合法
        try {
            JwtUtil.verify(req.getCheckKey());
            String target = JwtUtil.getUserKey(req.getCheckKey());
            BaseExceptionUtil.throwException(req.getMobile().equals(target), "");
        } catch (Exception e) {
            throw new BaseException("短信验证码校验通过标识异常，请重新进行验证");
        }

        // 校验手机号是否合法
        BaseExceptionUtil.throwException(RegexUtil.validateMobile(req.getMobile()), "邮箱格式错误");

        // 根据 用户ID，查询用户信息
        SysUser user = this.userDao.getById(req.getUserId());

        // 判断邮箱是否重复
        BaseExceptionUtil.throwException(!user.getEmail().equals(req.getMobile()), "新手机号与原手机号重复");

        // 根据手机号查询用户信息
        List<SysUser> userList =  this.userDao.listByMobile(req.getMobile())
                .stream().filter(x -> x.getId().intValue() != user.getId()).collect(Collectors.toList());

        // 判断手机号是否重复
        BaseExceptionUtil.throwException(CollectionUtils.isEmpty(userList), "该手机号已被其他账号使用");

        // 更新用户手机号
        SysUser updateMobileUser = new SysUser();
        updateMobileUser.setMobile(req.getMobile());
        updateMobileUser.setId(user.getId());
        updateMobileUser.setLastUpdateTime(LocalDateTime.now());
        this.userDao.updateById(updateMobileUser);

        // 异步更新缓存的用户信息
        BaseThreadUtil.async(() -> {
            // 查询最新的用户信息
            SysUser sysUser = this.userDao.getById(req.getUserId());

            // 组装用户信息缓存key
            String cacheKey = RedisAuthorizationConstant.AUTHORIZATION_USER_PREFIX + sysUser.getId();

            // 缓存用户信息
            this.redisCache.setObject(cacheKey, sysUser, 2, TimeUnit.DAYS);
        });
    }

    public BaseModelResponse<String> updateEmailOrMobileVerifyCodeCheck(UserUpdateEmailOrMobileVerifyCodeCheckAReq req) {
        // 参数校验
        BaseExceptionUtil.throwException(StringUtils.isNotBlank(req.getTarget()), "验证码目标为空");
        BaseExceptionUtil.throwException(StringUtils.isNotBlank(req.getVerifyCode()), "验证码为空");
        BaseExceptionUtil.throwException(Objects.nonNull(req.getWorkType()), "验证码业务类型为空");

        // 校验验证码
        this.commonService.checkVerifyCode(req.getWorkType(), req.getTarget(), req.getVerifyCode());

        // 未抛出异常则表明验证码校验通过，生成一个校验通过标识，12 分钟有效期
        String checkKey = JwtUtil.getToken(req.getTarget(), 60 * 12);

        // 将生成的标识返回
        return new BaseModelResponse<>(checkKey);
    }

}
